#include "sound.h"
#include "spinlock.h"
#include "console.h"
#include "riscv.h"
#include <string.h>
#define min(a, b) (((a) < (b)) ? (a) : (b))

desc *tx_ring, *rx_ring;
uint32 *regs;

spinlock_t sound_sleep_lock, sc_node_lock, tx_ring_lock, sound_recv_lock, recv_node_lock;

short top;
sc_node sc_nodes[SC_NODES_SIZE]; // 声卡分区相关属性
recv_node recv_nodes[RECV_NODE_SIZE]; // 接收节点链表，这里使用数组模拟链表，有点类似图论中邻接表常用的前向星存储
int free_stack[RECV_NODE_SIZE], stacktop, recv_node_cnt; // 分配节点相关，有一个空闲节点池

void sound_init() {
    // 把变量们绑定到声卡对应的地址
    char *base = (char *)SOUND_CARD_MEM_BASE;
    regs = (uint32 *)base;
    base += REGS_SIZE * sizeof(uint32);
    tx_ring = (desc *)base;
    base += sizeof(desc) * RINGS_SIZE;
    rx_ring = (desc *)base;
    for (int i = 0; i < SC_NODES_SIZE; i++) {
        sc_nodes[i].used = 0; sc_nodes[i].recv_head = -1;
    }
    stacktop = recv_node_cnt = 0;
    initlock(&sound_sleep_lock, "sound_sleep_lock");
    initlock(&sc_node_lock, "sc_node_lock");
    initlock(&tx_ring_lock, "tx_ring_lock");
    initlock(&sound_recv_lock, "sound_recv_lock");
    initlock(&recv_node_lock, "recv_node_lock");
}

short sound_open(){
    acquire(&sc_node_lock);
    // 寻找一个没有被用过的声卡分区，进行初始化
    for (short i = 0; i < SC_NODES_SIZE; i++) if (! sc_nodes[i].used) {
        sc_nodes[i].used = 1; sc_nodes[i].p = myproc();
        sc_nodes[i].read_offset = sc_nodes[i].write_offset = 0;
        release(&sc_node_lock);
        return i;
    }
    release(&sc_node_lock);
    return -1;
}

void sound_close(short id){
    acquire(&recv_node_lock);
    for (int i = sc_nodes[id].recv_head; i != -1; i = recv_nodes[i].next)
        free_stack[stacktop++] = i;
    release(&recv_node_lock);
    acquire(&sc_node_lock);
    sc_nodes[id].recv_head = -1;
    sc_nodes[id].used = 0;
    release(&sc_node_lock);
}

ssize_t sound_write(short m, const void * data, size_t len){
    uint32 i = 0;
    // 把data分成大小小于等于MBUF_SIZE的小块进行发送
    while (i < len) {
        uint32 frag_len = min(len - i, MBUF_SIZE);
        ssize_t r = sound_transmit(m, data + i, frag_len, sc_nodes[m].write_offset);
        if (r < 0) return r;
        sc_nodes[m].write_offset += frag_len;
        i += frag_len;
    }
    return len;
}

ssize_t sound_read(short m, void *data, size_t len) {
    // 如果下面第三行开始的循环循环体内无内容,则s指针声明需要加上volatile,因为这个变量
    // 会通过中断修改,编译器不知道这个情况可能会直接把该变量用寄存器存,内存值改了循环也不能结束
    uint32 been_read = 0; sc_node *s = sc_nodes + m;
    while (been_read < len) {
        while (s->recv_head == -1) {
            acquire(&sound_sleep_lock);
            do_sleep(s->p, &sound_sleep_lock);
            release(&sound_sleep_lock);
        }
        acquire(&sound_recv_lock);
        // 找到当前分区的read_offset所在的块进行读取
        for (int i = s->recv_head, j = -1; i != -1; j = i, i = recv_nodes[i].next) {
            struct recv_node *r = recv_nodes + i;
            if (s->read_offset >= r->offset &&
                    s->read_offset < r->offset + r->length) {
                // printk("sound_read:%d\n", s->read_offset);
                uint32 read_len = min(r->offset + r->length - s->read_offset, len - been_read);
                memcpy((char *)data + been_read, r->mbuf + s->read_offset - r->offset, read_len);
                s->read_offset += read_len; been_read += read_len;

                if (s->read_offset >= r->offset + r->length) {
                    // 一整块都被读完了,就得被删掉
                    if (j == -1) s->recv_head = r->next;
                    else recv_nodes[j].next = r->next;
                    free_stack[stacktop++] = i;
                }
            }
        }
        release(&sound_recv_lock);
    }
    return len;
}

ssize_t sound_transmit(short m, const void * data, uint32 len, uint32 offset) {
    acquire(&tx_ring_lock);
    uint32 index = regs[SOUND_TXC]; 
    if (tx_ring[index].status != RING_READY){
        release(&tx_ring_lock);
        return -1;
    }
    tx_ring[index].minor = m;
    tx_ring[index].offset = offset;
    tx_ring[index].length = len;
    memcpy(tx_ring[index].mbuf, (const char *)data, len);

    regs[SOUND_TXC] = (index + 1) % RINGS_SIZE;
    release(&tx_ring_lock);
    return 0;
}

void sound_recv() {
    acquire(&sound_recv_lock);
    for (;;) {
        uint32 index = (regs[SOUND_RXC] + 1) % RINGS_SIZE;
        if (rx_ring[index].status != RING_READY) break;

        sc_node *s = sc_nodes + rx_ring[index].minor;
        acquire(&recv_node_lock);
        if (stacktop == 0 && recv_node_cnt == RECV_NODE_SIZE) do_panic("Sound: receive more than read!");
        int recv_num = stacktop == 0 ? recv_node_cnt++ : free_stack[--stacktop];
        release(&recv_node_lock);

        // 从rx_ring中复制到recv_nodes里
        recv_nodes[recv_num].offset = rx_ring[index].offset;
        recv_nodes[recv_num].length = rx_ring[index].length;
        // printk("sound_recv:%d %d %d\n", index, rx_ring[index].offset, rx_ring[index].length);
        memcpy(recv_nodes[recv_num].mbuf, rx_ring[index].mbuf, rx_ring[index].length);
        recv_nodes[recv_num].next = s->recv_head;
        s->recv_head = recv_num; regs[SOUND_RXC] = index;
        rx_ring[index].status = ! RING_READY;
        // 对应分区能够读到东西了，需唤醒该进程
        wakeup(s->p);
    }
    release(&sound_recv_lock);
}

